﻿using System;
using System.Collections.Generic;
using System.Text;
using SecureConnection.Utils;

namespace RemoteCode.Remote
{
    public class SharedVariable : IDisposable
    {
        internal SharedVariable(string name_, object value, Nexum host_)
        {
            this.val = value;
            this.Name = name_;
            this.host = host_;
            this.Disposed = false;
        }

        object val;
        public string Name { get; protected set; }
        Nexum host;
        public bool Disposed { get; private set; }

        public T Get<T>()
        {
            return (T)val;
        }
        public object Get()
        {
            return val;
        }

        public void Set(object value)
        {
            if (Disposed)
                throw new Exception("Disposed");

            lock (host.SharedVariables)
            {
                ByteArrayWriter bw = new ByteArrayWriter();

                bw.WriteString(Name);

                if (value != null)
                {
                    byte[] buffer = SerializationHelper.Serialize(value);
                    bw.WriteInt(buffer.Length);
                    bw.WriteBytes(buffer);
                }
                else { bw.WriteInt(0); }

                Result r = host.GetResult(ref bw, NexumId.SetVariable);

                val = value;
            }
        }

        internal void Dispose_(bool remove = true)
        {
            lock (host.SharedVariables)
            {
                if(remove)
                    if (host.SharedVariables.ContainsKey(Name))
                        host.SharedVariables.Remove(Name);

                val = null;
                Name = null;
            }
        }
        public void Dispose()
        {
            if (Disposed)
                return;

            Disposed = true;

            ByteArrayWriter bw = new ByteArrayWriter();

            bw.WriteString(Name);

            Dispose_();

            Result r = host.GetResult(ref bw, NexumId.DisposeVariable);
        }

        internal static Result Dispose(ref ByteArrayReader br, Nexum host)
        {
            lock (host.SharedVariables)
            {
                string name = null;
                try
                {
                    name = br.ReadString();

                    if (!host.SharedVariables.ContainsKey(name))
                        return new Result(true, null, NexumError.SharedVariableNotFound, null);
                }
                catch (Exception ex)
                {
                    return new Result(true, ex, NexumError.PacketParsingError, null);
                }

                host.SharedVariables[name].Dispose_();

                return new Result(false, null, NexumError.Success, null);
            }
        }
        internal static Result Set(ref ByteArrayReader br, Nexum host)
        {
            lock (host.SharedVariables)
            {
                string name = null;
                object obj = null;

                try
                {
                    name = br.ReadString();
                    int length = br.ReadInt();
                    obj = length == 0 ? null : SerializationHelper.Deserialize(br.ReadBytes(length));
                }
                catch (Exception ex)
                {
                    return new Result(true, ex, NexumError.PacketParsingError, null);
                }

                if (!host.SharedVariables.ContainsKey(name))
                    host.SharedVariables.Add(name, new SharedVariable(name, obj, host));
                else host.SharedVariables[name].val = obj;

                return new Result(false, null, NexumError.Success, null);
            }
        }
    }
}
